/*!
 * \file imap_core.c
 *
 * \brief 共通定义
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 * 共通使用的宏和结构体
 *
 * \version 1.0
 * \author jikw
 * \date 2015/07/13
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "config.h"
#include "frct_comm.h"
#include "iconv2utf8.h"
#include "frreport_comm.h"
#include "frservice_comm.h"
#include "imap_core.h"

extern void *g_p_apm_context;

typedef struct __st_L7session_imap_private
{
    unsigned long ul_seq;                             //序列号，1次req和response时，使用同一个序列号
    L4_transaction st_l4_trans;                       //数据
    L7_transaction st_l7_trans;                       //数据
    int i_flag_data_type;                             //1: FRLOGIN_START 2:FRLOGIN_SUCC 3:FRLOGIN_FAIL 4 FRLOGOUT_START 5 FRLOGOUT_END 0 : other
    Frreport_body_data *p_st_body_data_req;
    Frreport_body_data *p_st_body_data_resp;
    Frlist_header *p_lst_comm;
    Frlist_header *p_lst_req;
    int i_response_sign;                              //标志位 0||1, 0:未传进来response 1:传进来过response
    int i_flag_response;                              //标志位 0||1, 0:response的code和string不必上报 1：需要上报
    char *p_stay;                                     //指向上次传来的response最后一行
    char *p_cmd;                                      //保存命令
    char *p_user_name;
    char *p_header_name;
    struct timeval st_login_timestamp;
    char arr_session_id[APM_UUID_SIZE];
}L7session_imap_private;

/*!
 * 逆序查找字符串(所查字符串在末尾不计)
 *
 * \param p_data
 * \param i_data_len
 * \param p_substr
 * \param i_sublen
 *
 * \return NULL     查找无结果\n
 *         p_temp   查找到
 *
 * \note
 *
 */
FR_STATIC char * nefrmemstr(const char * p_data, int i_data_len, char * p_substr, int i_sublen)
{
    int i_count = 0;
    int i_check_len = 0;
    char * p_temp = NULL;

    if (p_data == NULL || i_data_len <= 0
        || p_substr == NULL || i_sublen <= 0
        || i_sublen > i_data_len )
        return NULL;

    i_check_len = i_data_len - i_sublen + 1;
    //p_temp指向p_cur的倒数i_sublen-1个字节
    p_temp = (char *) (p_data+i_data_len-i_sublen-1);
    for (i_count = 0; i_count < i_check_len; i_count++)
    {
        if (*p_temp == *p_substr)
        {
            if (memcmp(p_temp, p_substr, i_sublen) == 0)
            {
                return p_temp;
            }
        }
        p_temp--;
    }

    return NULL;
}

/*!
 * imap私有数据创建
 *
 * \param void
 *
 * \return NULL           内存分配失败\n
 *         p_st_private   成功
 *
 * \note
 *
 */
FR_STATIC L7session_imap_private* __imap_private_create(void)
{
    L7session_imap_private *p_st_private = NULL;

    p_st_private = (L7session_imap_private*)frmalloc(sizeof(L7session_imap_private));
    if (p_st_private == NULL)
        return NULL;
    memset(p_st_private, 0x00, sizeof(L7session_imap_private));
    return p_st_private;
}

/*!
 * 私有信息初始化
 *
 * \param p_private_session    (imap的私有session数据)
 *
 * \return FR_SUCC              成功
 *
 * \note
 *
 */
FR_STATIC int __imap_session_reset(void *p_private_session)
{
    L7session_imap_private *p_st_private = (L7session_imap_private*)p_private_session;
    if (p_st_private)
    {
        if (p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        if (p_st_private->p_st_body_data_resp)
            frreport_body_free(&p_st_private->p_st_body_data_resp);

        if (p_st_private->p_lst_req)
            frreport_body_l7list_free(&p_st_private->p_lst_req);

        if (p_st_private->p_lst_comm)
            frreport_body_l7list_free(&p_st_private->p_lst_comm);

        if (p_st_private->p_header_name)
        {
            frfree(p_st_private->p_header_name);
            p_st_private->p_header_name = NULL;
        }

        if (p_st_private->p_stay)
        {
            frfree(p_st_private->p_stay);
            p_st_private->p_stay = NULL;
        }

        if (p_st_private->p_cmd)
        {
            frfree(p_st_private->p_cmd);
            p_st_private->p_cmd = NULL;
        }

        memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
        p_st_private->i_flag_data_type = 0;
        p_st_private->i_response_sign = 0;
        p_st_private->i_flag_response = 0;
    }
    return FR_SUCC;
}

/*!
 * 判断是否是imap协议
 *
 * \param p_st_conn       (输入数据信息)
 * \param p_st_packet     (输入数据)
 *
 * \return APM_L7_IS_YES  属于imap协议\n
 *         APM_L7_IS_NO   不属于imap协议
 *
 * \note
 *
 */
int imap_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = 0;
    int i_ret_fun = 0;
    char *p_pos = NULL;

    if (p_st_packet == NULL || p_st_packet->p_payload == NULL || p_st_packet->ui_payload_len <= 3 || p_st_conn==NULL)
        return APM_L7_IS_NO;

    //查找response的倒数第二个\r\n。
    p_pos = nefrmemstr(p_st_packet->p_payload, p_st_packet->ui_payload_len, (char *)"\r\n", 2);
    //单行response情况
    if (p_pos == NULL)
    {
        //查找第一个空格
        p_pos = (char *)memchr(p_st_packet->p_payload, ' ', p_st_packet->ui_payload_len);
        if (p_pos == NULL)
            goto error;
        if (strncmp(p_pos, " OK ", 4) != 0 && strncmp(p_pos, " NO ", 4) != 0 && strncmp(p_pos, " BAD ", 5) != 0)
            goto error;
    }
    //多行response情况
    else
    {
        //查找最后一行的第一个空格
        p_pos = (char *)memchr(p_pos, ' ', p_st_packet->ui_payload_len-(p_pos-p_st_packet->p_payload));
        if (p_pos == NULL)
            goto error;
        if (strncmp(p_pos, " OK ", 4) != 0 && strncmp(p_pos, " NO ", 4) != 0 && strncmp(p_pos, " BAD ", 5) != 0)
            goto error;
    }

    i_ret_fun = frct_get_direct_known(p_st_conn);
    //方向明确
    if (i_ret_fun == FR_DIRECT_KNOWN)
    {
        frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0);
        return APM_L7_IS_YES;
    }
    //方向不明确
    else
    {
        if (frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port) != FR_SUCC)
        {
            frdbg("frcap_set_cs_srv failed\n");
            return APM_L7_IS_NO;
        }
        p_st_conn->flg_direct_known = FR_DIRECT_KNOWN;
        frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0);
        return APM_L7_IS_YES;
    }

error:
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            return APM_L7_IS_YES;
        }
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            return APM_L7_IS_YES;
        }
    }
    else
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;

        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }
    return APM_L7_IS_NO;
}

/*!
 * req数据解析
 *
 * \param p_data         (req数据)
 * \param ui_data_len    (数据长度)
 * \param p_st_private   (私有数据)
 * \param p_st_body_data
 * \param p_st_conn
 *
 * \return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC)   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *
 * \note
 *
 */
FR_STATIC int __req_parse(char *p_data, unsigned int ui_data_len, L7session_imap_private *p_st_private, Frreport_body_data *p_st_body_data, Conntrack *p_st_conn)
{
    int i_value_len = 0;
    int i_value_len_new = 0;
    int i_new_len = 0;
    int i_sign_uft7 = 0;
    unsigned int ui_len_tmp = 0;
    char *p_tmp = NULL;
    char *p_name = NULL;
    char *p_value = NULL;
    char *p_pos = NULL, *p_pos2 = NULL,*p_pos3 = NULL;
    char *p_field_value_tmp = NULL;
    char *p_field_value_tmp_new = NULL;
    char *p_new_data = NULL;
    char arr_tmp[16];
    char arr_charset[16];
    char arr_utf7[32];
    char arr_utf7_tmp[32];
    char arr_tmp_eng[1024];

    if (p_data == NULL || ui_data_len == 0 || p_st_private == NULL || p_st_body_data == NULL || p_st_conn == NULL)
        return APM_L7_ANALYZE_FAIL;

    memset(arr_tmp, 0x00, sizeof(arr_tmp));
    memset(arr_charset, 0x00, sizeof(arr_charset));
    memset(arr_utf7, 0x00, sizeof(arr_utf7));
    memset(arr_utf7_tmp, 0x00, sizeof(arr_utf7_tmp));
    memset(arr_tmp_eng, 0x00, sizeof(arr_tmp_eng));

    snprintf(arr_charset, sizeof(arr_charset), "%s", "utf-7");
    //查找request的第一个空格
    p_pos = (char *)memchr(p_data, ' ', ui_data_len);
    if (p_pos == NULL)
        goto ERROR;
    if (strncmp(p_pos+1, "CREATE ", 7) == 0 || strncmp(p_pos+1, "DELETE ", 7) == 0 || strncmp(p_pos+1, "SELECT ", 7) == 0)
    {
        //查找第二个空格
        p_pos2 = (char *)memchr(p_pos+1, ' ', ui_data_len-(p_pos-p_data)-1);
        if (p_pos2 == NULL)
            goto ERROR;
        //如果文件夹以中文命名，即以&开头，如C27 CREATE "&ZYdO9g-"\r\n
        if (*(p_pos2+2) == '&')
        {
            //arr_utf7保存+ZYdO9g-
            snprintf(arr_utf7,ui_data_len-(p_pos2-p_data)-4, "+%s", p_pos2+3);
            //utf-7转utf-8
            if (iconv_to_utf8(arr_utf7, ui_data_len-(p_pos2-p_data)-5, arr_charset, &p_field_value_tmp, (unsigned int *)&i_value_len) == FR_FAIL)
                goto ERROR;
            //标志位，之后frfree(p_new_data)用
            i_sign_uft7 = 1;
            //p_new_data保存C27 CREATE "文件"\r\n
            p_new_data = (char *)frmalloc(p_pos2-p_data+5+i_value_len);
            if (p_new_data == NULL)
                goto ERROR;
            //arr_tmp保存C27 CREATE
            snprintf(arr_tmp, p_pos2-p_data+1, "%s", p_data);
            snprintf(p_new_data,p_pos2-p_data+5+i_value_len, "%s '%s'\r\n", arr_tmp, p_field_value_tmp);
            frfree(p_field_value_tmp);
            i_new_len = p_pos2-p_data+5+i_value_len;
        }
        else
        {
            p_new_data = p_data;
            i_new_len = ui_data_len;
        }
    }
    else if (strncmp(p_pos+1, "RENAME ", 7) == 0)
    {
        //查找第二个空格
        p_pos2 = (char *)memchr(p_pos+1, ' ', ui_data_len-(p_pos-p_data)-1);
        if (p_pos2 == NULL)
            goto ERROR;
        //查找第三个空格
        p_pos3 = (char *)memchr(p_pos2+1, ' ', ui_data_len-(p_pos2-p_data)-1);
        if (p_pos3==NULL)
            goto ERROR;
        //如果旧文件夹以中文命名，即以&开头，如C29 RENAME "&ZYdO9g-" "&f1FmEw-"\r\n
        if (*(p_pos2+2) == '&')
        {
            //arr_utf7保存+ZYdO9g-
            snprintf(arr_utf7,p_pos3-p_pos2-2, "+%s", p_pos2+3);
            //utf-7转utf-8
            if (iconv_to_utf8(arr_utf7, p_pos3-p_pos2-3, arr_charset, &p_field_value_tmp, (unsigned int *)&i_value_len) == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;
        }
        else
        {
            //arr_utf7保存旧文件名
            snprintf(arr_utf7_tmp, p_pos3-p_pos2-2, "%s", p_pos2+2);
            p_field_value_tmp = arr_utf7_tmp;
        }

        //如果新文件夹以中文命名
        if (*(p_pos3+2) == '&')
        {
            //arr_utf7保存+f1FmEw-
            snprintf(arr_utf7,ui_data_len-(p_pos3-p_data)-4, "+%s", p_pos3+3);
            //utf-7转utf-8
            if (iconv_to_utf8(arr_utf7, ui_data_len-(p_pos3-p_data)-5, arr_charset, &p_field_value_tmp_new, (unsigned int *)&i_value_len_new) == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;

            //标志位，之后frfree(p_new_data)用
            i_sign_uft7 = 1;
            if (*(p_pos2+2) == '&')
                p_new_data = (char *)frmalloc(p_pos2-p_data+8+i_value_len+i_value_len_new);
            else
                p_new_data = (char *)frmalloc(p_pos3-p_data+5+i_value_len_new);
            if (p_new_data == NULL)
                goto ERROR;
            //arr_tmp保存C29 RENAME
            snprintf(arr_tmp, p_pos2-p_data+1, "%s", p_data);
            if (*(p_pos2+2) == '&')
                snprintf(p_new_data,p_pos2-p_data+8+i_value_len+i_value_len_new, "%s '%s' '%s'\r\n", arr_tmp, p_field_value_tmp, p_field_value_tmp_new);
            else
                snprintf(p_new_data,p_pos3-p_data+5+i_value_len_new, "%s '%s' '%s'\r\n", arr_tmp, p_field_value_tmp, p_field_value_tmp_new);
            if (*(p_pos2+2) == '&')
                frfree(p_field_value_tmp);
            frfree(p_field_value_tmp_new);
            if (*(p_pos2+2) == '&')
                i_new_len = p_pos2-p_data+8+i_value_len+i_value_len_new;
            else
                i_new_len = p_pos3-p_data+5+i_value_len_new;
        }
        else
        {
            //标志位，之后frfree(p_new_data)用
            i_sign_uft7 = 1;
            if (*(p_pos2+2) == '&')
                p_new_data = (char *)frmalloc(ui_data_len-(p_pos3-p_pos2)+i_value_len+3);
            else
                p_new_data = (char *)frmalloc(ui_data_len+1);
            if (p_new_data == NULL)
                goto ERROR;
            //arr_tmp保存C29 RENAME
            snprintf(arr_tmp, p_pos2-p_data+1, "%s", p_data);
            //arr_tmp保存"test"\r\n
            snprintf(arr_tmp_eng, ui_data_len-(p_pos3-p_data)+1, "%s", p_pos3+1);
            if (*(p_pos2+2) == '&')
                snprintf(p_new_data,ui_data_len-(p_pos3-p_pos2)+i_value_len+3, "%s '%s' %s", arr_tmp, p_field_value_tmp, arr_tmp_eng);
            else
                snprintf(p_new_data,ui_data_len+1, "%s '%s' %s", arr_tmp, p_field_value_tmp, arr_tmp_eng);
            if (*(p_pos2+2) == '&')
                frfree(p_field_value_tmp);
            if (*(p_pos2+2) == '&')
                i_new_len = ui_data_len-(p_pos3-p_pos2)+i_value_len+3;
            else
                i_new_len = ui_data_len;
        }
    }
    else if (strncmp(p_pos+1, "APPEND ", 7) == 0 || strncmp(p_pos+1, "STATUS ", 7) == 0)
    {
        //查找第二个空格
        p_pos2 = (char *)memchr(p_pos+1, ' ', ui_data_len-(p_pos-p_data)-1);
        if (p_pos2 == NULL)
            goto ERROR;
        //查找第三个空格
        p_pos3 = (char *)memchr(p_pos2+1, ' ', ui_data_len-(p_pos2-p_data)-1);
        if (p_pos3==NULL)
            goto ERROR;
        //如果文件夹以中文命名
        if (*(p_pos2+2) == '&')
        {
            //arr_utf7保存+ZYdO9g-
            snprintf(arr_utf7, p_pos3-p_pos2-2, "+%s", p_pos2+3);
            //utf-7转utf-8
            if (iconv_to_utf8(arr_utf7, p_pos3-p_pos2-3, arr_charset, &p_field_value_tmp, (unsigned int *)&i_value_len) == FR_FAIL)
                goto ERROR;
            //标志位，之后frfree(p_new_data)用
            i_sign_uft7 = 1;
            //p_new_data保存C27 CREATE "文件"\r\n
            p_new_data = (char *)frmalloc(ui_data_len-(p_pos3-p_pos2)+4+i_value_len);
            if (p_new_data == NULL)
                goto ERROR;
            //arr_tmp保存C27 APPEND
            snprintf(arr_tmp, p_pos2-p_data+1, "%s", p_data);
            //arr_tmp_eng保存文件名之后参数
            snprintf(arr_tmp_eng, ui_data_len-(p_pos3-p_data)+1, "%s", p_pos3+1);
            snprintf(p_new_data, ui_data_len-(p_pos3-p_pos2)+4+i_value_len, "%s '%s' %s", arr_tmp, p_field_value_tmp, arr_tmp_eng);
            frfree(p_field_value_tmp);
            i_new_len = ui_data_len-(p_pos3-p_pos2)+3+i_value_len;
        }
        else
        {
            p_new_data = p_data;
            i_new_len = ui_data_len;
        }
    }
    else
    {
        p_new_data = p_data;
        i_new_len = ui_data_len;
    }

    //查找request的第一个空格
    p_pos = (char *)memchr(p_new_data, ' ', i_new_len);
    if (p_pos == NULL)
        goto ERROR;
    //查找request的第二个空格
    p_pos2 = (char *)memchr(p_pos + 1, ' ', i_new_len-(p_pos-p_new_data)-1);
    if (p_pos2 == NULL)
    {
        //i_new_len-(p_pos-p_new_data)-2去除\r\n
        p_name = (char *)frmalloc(i_new_len-(p_pos-p_new_data)-2);
        if (p_name == NULL)
            goto ERROR;
        snprintf(p_name,i_new_len-(p_pos-p_new_data)-2, "%s", p_pos+1);
        if (strncmp(p_name, "LOGOUT", 6) == 0)
            p_st_private->i_flag_data_type = 4;

        if (strncasecmp(p_name, "EXPUNGE", 7) == 0 || strncmp(p_name, "LOGOUT", 6) == 0)
        {
            p_st_private->i_flag_response = 1;
            if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_name) == FR_FAIL)
                goto ERROR;
            if (frreport_body_l7_add_str(p_st_body_data, "request.imap.cmd", p_name) == FR_FAIL)
                goto ERROR;
        }
        p_st_private->p_cmd = p_name;
        p_name = NULL;
        return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
    }
    else
    {
        if (strncmp(p_pos+1, "UID ", 4) == 0)
        {
            //查找request的第三个空格
            p_pos3 = (char *)memchr(p_pos2 + 1, ' ', i_new_len-(p_pos2-p_new_data)-1);
            if (p_pos3 == NULL)
                return APM_L7_ANALYZE_FAIL;
            ui_len_tmp =  p_pos3 - p_pos;
            p_name = (char *)frmalloc(ui_len_tmp);
            if (p_name == NULL)
                goto ERROR;
            snprintf(p_name,ui_len_tmp, "%s", p_pos+1);

            if (strncasecmp(p_name, "UID FETCH", 9)==0 || strncasecmp(p_name, "UID STORE", 9)==0)
            {
                p_st_private->i_flag_response = 1;
                p_tmp = (char *)frmalloc(i_new_len-(p_pos-p_new_data)-2);
                if (p_tmp == NULL)
                    goto ERROR;
                snprintf(p_tmp,i_new_len-(p_pos-p_new_data)-2, "%s", p_pos+1);
                if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_tmp) == FR_FAIL)
                    goto ERROR;
                frfree(p_tmp);
                p_tmp = NULL;

                if (frreport_body_l7_add_str(p_st_body_data, "request.imap.cmd", p_name) == FR_FAIL)
                    goto ERROR;
            }
            p_st_private->p_cmd = p_name;
            p_name = NULL;
            //之前设置COMMAND为第一个与第三个空格之间的字符串，之后设置PARAMETER为第三个空格之后的字符串。
            ui_len_tmp = i_new_len-(p_pos3-p_new_data)-2;
            p_value = (char *)frmalloc(ui_len_tmp);
            if (p_value == NULL)
                goto ERROR;
            snprintf(p_value, ui_len_tmp, "%s", p_pos3+1);

            if (frreport_body_l7_add_str(p_st_body_data, "request.imap.param", p_value) == FR_FAIL)
                goto ERROR;
            frfree(p_value);
            p_value = NULL;
            return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
        }
        else
        {
            if (strncmp(p_pos+1, "LOGIN", 5) == 0)
            {
                p_st_private->i_flag_response = 0;
                p_st_private->i_flag_data_type = 1;
                fruuid(p_st_private->arr_session_id);

                p_st_private->p_cmd = (char *)frmalloc(6);
                if (p_st_private->p_cmd == NULL)
                    goto ERROR;
                snprintf(p_st_private->p_cmd, 6, "%s", "LOGIN");

                //查找第三个空格,p_value存“账户名”
                p_pos = (char *)memchr(p_pos2 + 1, ' ', i_new_len-(p_pos2-p_new_data)-1);
            	if (p_pos == NULL)
            	    return APM_L7_ANALYZE_FAIL;
            	ui_len_tmp = p_pos-p_pos2;
            	p_value = (char *)frmalloc(ui_len_tmp);
		        if (p_value == NULL)
		            goto ERROR;
		        snprintf(p_value, ui_len_tmp, "%s", p_pos2+1);
                if (p_st_private->p_user_name)
                    frfree(p_st_private->p_user_name);
		        p_st_private->p_user_name = p_value;
                p_value = NULL;

                p_st_private->st_login_timestamp.tv_sec = p_st_private->st_l4_trans.st_request_time_first_byte.tv_sec;
                p_st_private->st_login_timestamp.tv_usec = p_st_private->st_l4_trans.st_request_time_first_byte.tv_usec;

                if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, "LOGIN") == FR_FAIL)
                    goto ERROR;
		        if (frreport_body_l7_add_str(p_st_body_data, "request.imap.cmd", "LOGIN") == FR_FAIL)
		            goto ERROR;
                return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            }
            ui_len_tmp =  p_pos2 - p_pos;
            p_name = (char *)frmalloc(ui_len_tmp);
            if (p_name == NULL)
                goto ERROR;
            snprintf(p_name,ui_len_tmp, "%s", p_pos+1);

            if (strncasecmp(p_name, "APPEND", 6)==0)
            {
                p_st_private->i_flag_response = 1;
                //查找request的第三个空格
                p_pos3 = (char *)memchr(p_pos2 + 1, ' ', i_new_len-(p_pos2-p_new_data)-1);
                if (p_pos3 == NULL)
                    goto ERROR;
                p_tmp = (char *)frmalloc(p_pos3 - p_pos);
                if (p_tmp == NULL)
                    goto ERROR;
                snprintf(p_tmp,p_pos3 - p_pos, "%s", p_pos+1);
                if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_tmp) == FR_FAIL)
                    goto ERROR;
                frfree(p_tmp);
                p_tmp = NULL;

                if (frreport_body_l7_add_str(p_st_body_data, "request.imap.cmd", p_name) == FR_FAIL)
                    goto ERROR;
                p_st_private->p_cmd = p_name;
                p_name = NULL;
                //之前设置COMMAND为第一个与第二个空格之间的字符串，之后设置PARAMETER为第二个空格之后的字符串。
                ui_len_tmp = i_new_len-(p_pos2-p_new_data)-2;
                p_value = (char *)frmalloc(ui_len_tmp);
                if (p_value == NULL)
                    goto ERROR;
                snprintf(p_value, ui_len_tmp, "%s", p_pos2+1);

                if (frreport_body_l7_add_str(p_st_body_data, "request.imap.param", p_value) == FR_FAIL)
                    goto ERROR;
                frfree(p_value);
                p_value = NULL;
                if (i_sign_uft7)
                    frfree(p_new_data);
                return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            }
            if (strncasecmp(p_name, "CREAT", 5)==0 || strncasecmp(p_name, "DELETE", 6)==0 ||strncasecmp(p_name, "RENAME", 6)==0
                ||strncasecmp(p_name, "FETCH", 5)==0 || strncasecmp(p_name, "STATUS", 6)==0 ||strncasecmp(p_name, "STORE", 5)==0
                ||strncasecmp(p_name, "EXPUNGE", 7)==0||strncasecmp(p_name, "LIST", 4)==0||strncasecmp(p_name, "SELECT", 6)==0)
            {
                p_st_private->i_flag_response = 1;
                if (strncasecmp(p_name, "STATUS", 6)==0)
                {
                    p_pos3 = frmemstr(p_pos2 + 1, i_new_len-(p_pos2-p_new_data)-1, (char *)" (", 2);
                    if (p_pos3 == NULL)
                        goto ERROR;
                    p_tmp = (char *)frmalloc(p_pos3-p_pos+1);
                    if (p_tmp == NULL)
                        goto ERROR;
                    snprintf(p_tmp,p_pos3-p_pos, "%s", p_pos+1);
                    if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_tmp) == FR_FAIL)
                        goto ERROR;
                    frfree(p_tmp);
                    p_tmp = NULL;
                }
                else
                {
                    p_tmp = (char *)frmalloc(i_new_len-(p_pos-p_new_data)-2);
                    if (p_tmp == NULL)
                        goto ERROR;
                    snprintf(p_tmp,i_new_len-(p_pos-p_new_data)-2, "%s", p_pos+1);
                    if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_tmp) == FR_FAIL)
                        goto ERROR;
                    frfree(p_tmp);
                    p_tmp = NULL;
                }

                if (frreport_body_l7_add_str(p_st_body_data, "request.imap.cmd", p_name) == FR_FAIL)
                    goto ERROR;
                p_st_private->p_cmd = p_name;
                p_name = NULL;
                //之前设置COMMAND为第一个与第二个空格之间的字符串，之后设置PARAMETER为第二个空格之后的字符串。
                ui_len_tmp = i_new_len-(p_pos2-p_new_data)-2;
                p_value = (char *)frmalloc(ui_len_tmp);
                if (p_value == NULL)
                    goto ERROR;
                snprintf(p_value, ui_len_tmp, "%s", p_pos2+1);

                if (frreport_body_l7_add_str(p_st_body_data, "request.imap.param", p_value) == FR_FAIL)
                    goto ERROR;
                frfree(p_value);
                p_value = NULL;
                if (i_sign_uft7)
                    frfree(p_new_data);
                return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            }
            p_st_private->p_cmd = p_name;
            p_name = NULL;
            return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
        }
    }

ERROR:
    if (i_sign_uft7)
        frfree(p_new_data);
    if (p_name)
        frfree(p_name);
    if (p_value)
        frfree(p_value);
    if (p_tmp)
        frfree(p_tmp);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * resp数据解析
 *
 * \param p_data         (req数据)
 * \param ui_data_len    (数据长度)
 * \param p_st_private   (私有数据)
 * \param p_st_body_data
 * \param p_st_conn
 *
 * \return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC)   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *
 * \note
 *
 */
FR_STATIC int __resp_parse(char *p_data, unsigned int ui_data_len, L7session_imap_private *p_st_private, Frreport_body_data *p_st_body_data, Conntrack *p_st_conn)
{
    unsigned int ui_len_tmp = 0;
    char *p_header_value = NULL;
    char *p_pos = NULL, *p_pos2 = NULL;
    L7_transaction *p_st_l7_trans = NULL;

    if (p_data == NULL || ui_data_len == 0 || p_st_private == NULL || p_st_body_data == NULL || p_st_conn == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_l7_trans = &p_st_private->st_l7_trans;

    //查找第一个空格
    p_pos = (char *)memchr(p_data, ' ', ui_data_len);
    if (p_pos == NULL)
        return APM_L7_ANALYZE_FAIL;

    //判断是否为session数据
    if (p_st_private->i_flag_data_type == 4)
        p_st_private->i_flag_data_type = 5;
    if (p_st_private->i_flag_data_type == 1)
    {
        if (strncmp(p_pos, " OK", 3) == 0)
            p_st_private->i_flag_data_type = 2;
        else
            p_st_private->i_flag_data_type = 3;
    }

    if (strncmp(p_pos, " OK", 3) == 0)
        p_st_l7_trans->l_response_code = 0;
    else if (strncmp(p_pos, " NO", 3) == 0)
        p_st_l7_trans->l_response_code = -1;
    else if (strncmp(p_pos, " BAD", 4) == 0)
        p_st_l7_trans->l_response_code = -2;

    //查找第二个空格
    p_pos2 = (char *)memchr(p_pos+1, ' ', ui_data_len-(p_pos-p_data)-1);
    if (p_pos2 == NULL)
        return APM_L7_ANALYZE_FAIL;

    ui_len_tmp = ui_data_len-(p_pos2-p_data)-2;
    p_header_value = (char *)frmalloc(ui_len_tmp);
    if (p_header_value == NULL)
        goto ERROR;
    snprintf(p_header_value,ui_len_tmp,"%s",p_pos2+1);

    if (p_st_private->i_flag_response == 1)
    {
        //设置节点内容
        if (frreport_body_l7_add_int(p_st_body_data, APM_REPORT_KEY_RESP_CODE, p_st_l7_trans->l_response_code) == FR_FAIL)
            goto ERROR;
        if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_RESP_CODE_STRING, p_header_value) == FR_FAIL)
            goto ERROR;
        p_st_private->i_flag_response = 0;
    }
    frfree(p_header_value);
    p_header_value = NULL;
    return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);

ERROR:
    if (p_header_value)
        frfree(p_header_value);

    return APM_L7_ANALYZE_FAIL;
}

/*
*   imap session 数据上报
*/
FR_STATIC int __imap_session_report(Frreport_body_data *p_st_body_data, L7session_imap_private *p_st_private)
{
    if (p_st_body_data == NULL || p_st_private == NULL)
        return FR_FAIL;

    if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_SESSION_USERNAME, p_st_private->p_user_name) == FR_FAIL)
        return FR_FAIL;

    if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_SESSION_ID, p_st_private->arr_session_id) == FR_FAIL)
        return FR_FAIL;

    if (frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_SESSION_LOGIN_TIMESTAMP, &p_st_private->st_login_timestamp) == FR_FAIL)
        return FR_FAIL;

    return FR_SUCC;
}

/*!
 * imap的packet解析
 *
 * \param p_st_conn          (入力链接信息)
 * \param p_st_packet        (入力packet信息)
 * \param p_st_hash_report   (保存Frreport_data)
 * \param p_st_session       (私有数据)
 *
 * \return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC)   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *
 * \note
 *
 */
FR_STATIC int __req_data_analysis(Conntrack *p_st_conn
                                 , Apm_packet *p_st_packet
                                 , Frhash_header *p_st_hash_report
                                 , L7_session *p_st_session)
{
    int i_ret = 0;
    unsigned long ul_tmp = 0;
    L7session_imap_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    Frreport_data *p_st_report_data = NULL;

    if (p_st_conn == NULL || p_st_packet == NULL
        || p_st_hash_report == NULL || p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_private = (L7session_imap_private*)p_st_session->p_session_private;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    //如果连续的两个request
    if (p_st_private->p_lst_comm)
        __imap_session_reset((void *)(p_st_private));

    //创建数据链表
    if (p_st_private->p_st_body_data_req == NULL)
    {
        p_st_private->p_st_body_data_req = frreport_body_new_l7(p_st_conn);
        if (p_st_private->p_st_body_data_req == NULL)
            goto ERROR;

        if (frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_req, p_st_conn) == FR_FAIL)
            goto ERROR;

        //seq ++
        p_st_private->ul_seq = frct_seq_increase(p_st_conn);

        //st_request_time_first_byte
        p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;
    }

    //请求的字节数
    p_st_l4_trans->l_request_bytes += p_st_packet->ui_payload_len;

    //req解析
    i_ret = __req_parse(p_st_packet->p_payload, p_st_packet->ui_payload_len, p_st_private, p_st_private->p_st_body_data_req, p_st_conn);
    if (i_ret == APM_L7_ANALYZE_FAIL)
    {
        frreport_body_free(&p_st_private->p_st_body_data_req);
        return i_ret;
    }
    if (p_st_private->i_flag_response==0)
    {
        if (p_st_private->p_cmd)
        {
            frfree(p_st_private->p_cmd);
            p_st_private->p_cmd = NULL;
        }
        frreport_body_free(&p_st_private->p_st_body_data_req);
        return i_ret;
    }

    if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ID, p_st_private->ul_seq) == FR_FAIL)
        goto ERROR;

    //ResponseRequired
    if (frreport_body_l7_add_int(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1) == FR_FAIL)
        goto ERROR;

    //start time
    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_l4_trans->st_request_time_first_byte) == FR_FAIL)
        goto ERROR;

    //st_request_time
    p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    ul_tmp = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &(p_st_l4_trans->st_request_time));
    //send_time_us
    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    //request bytes
    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_l4_trans->l_request_bytes) == FR_FAIL)
        goto ERROR;

    //end time
    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_l4_trans->st_request_time) == FR_FAIL)
        goto ERROR;

    if (p_st_private->p_user_name)
    {
        if (__imap_session_report(p_st_private->p_st_body_data_req, p_st_private) == FR_FAIL)
            goto ERROR;
    }

    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
    if (p_st_report_data == NULL)
        goto ERROR;

    //拷贝相关链表
    p_st_private->p_lst_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_private->p_st_body_data_req);
    if (p_st_private->p_lst_comm == NULL)
        goto ERROR;
    p_st_private->p_lst_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_private->p_st_body_data_req);
    if (p_st_private->p_lst_req == NULL)
        goto ERROR;

    if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_req) == FR_FAIL)
        goto ERROR;
    p_st_private->p_st_body_data_req = NULL;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
        goto ERROR;
    p_st_report_data = NULL;

    return i_ret;

ERROR:
    if (p_st_report_data)
        frreport_data_free(&p_st_report_data);
    __imap_session_reset((void *)(p_st_private));
    return APM_L7_ANALYZE_FAIL;
}

/*!
 * imap的packet解析
 *
 * \param p_st_conn          (入力链接信息)
 * \param p_st_packet        (入力packet信息)
 * \param p_st_hash_report   (保存Frreport_data)
 * \param p_st_session       (私有数据)
 *
 * \return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC)   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *         APM_L7_ANALYZE_TODO   数据未结束
 *
 * \note
 *
 */
FR_STATIC int __resp_data_analysis(Conntrack *p_st_conn
                                 , Apm_packet *p_st_packet
                                 , Frhash_header *p_st_hash_report
                                 , L7_session *p_st_session)
{
    int i_ret = 0;
    int i_flag_todo = 1;
    unsigned long ul_tmp = 0;
    char *p_pos = NULL, *p_tmp = NULL;
    char arr_tmp1[64], arr_tmp2[64];
    L7session_imap_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    Frreport_data* p_st_report_data = NULL;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL || p_st_session == NULL)
        goto ERROR;

    memset(arr_tmp1, 0x00, sizeof(arr_tmp1));
    memset(arr_tmp2, 0x00, sizeof(arr_tmp2));

    p_st_private = (L7session_imap_private*)p_st_session->p_session_private;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    if (p_st_private->i_flag_response == 0)
        return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);

    if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0 && p_st_l4_trans->st_response_time_first_byte.tv_usec == 0)
    {
        //创建数据链表
        p_st_private->p_st_body_data_resp = frreport_body_new_l7(p_st_conn);
        if (p_st_private->p_st_body_data_resp == NULL)
            goto ERROR;

        if (p_st_l4_trans->st_request_time.tv_sec != 0)
        {
            FRREPORT_BODY_L7LIST_SET_REQ(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_req);
            FRREPORT_BODY_L7LIST_SET_COMM(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_comm);
        }
        else
        {
            if (frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_resp, p_st_conn) == FR_FAIL)
                goto ERROR;
        }

        p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

        //start time
        if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_l4_trans->st_response_time_first_byte) == FR_FAIL)
            goto ERROR;

        if (p_st_l4_trans->st_request_time.tv_sec != 0 || p_st_l4_trans->st_request_time.tv_usec != 0)
        {
            //server time
            ul_tmp = frtime_diff(&(p_st_l4_trans->st_request_time), &(p_st_l4_trans->st_response_time_first_byte));
            if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_tmp) == FR_FAIL)
                goto ERROR;
        }
        else
        {
            //如果不是第一个响应信息  并且没有req数据包  直接返回
            if (frmemstr(p_st_packet->p_payload, p_st_packet->ui_payload_len, (char *)"Server ready", 12) == NULL)
            {
                frreport_body_free(&p_st_private->p_st_body_data_resp);
                return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            }

            if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, 0) == FR_FAIL)
                goto ERROR;
        }
    }

    //如果响应为NO或BAD
    p_pos = (char *)memchr(p_st_packet->p_payload, ' ', p_st_packet->ui_payload_len);
    if (p_pos == NULL)
        goto ERROR;

    if (strncmp(p_pos, " NO ", 4) == 0 || strncmp(p_pos, " BAD ", 5) == 0)
    {
        if (p_st_private->p_cmd)
        {
            frfree(p_st_private->p_cmd);
            p_st_private->p_cmd=NULL;
        }
        //resp解析
        i_ret = __resp_parse(p_st_packet->p_payload, p_st_packet->ui_payload_len, p_st_private, p_st_private->p_st_body_data_resp, p_st_conn);
        if (i_ret != APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC))
            return i_ret;
    }
    else
    {
        if (p_st_private->p_cmd)
        {
            if (strncmp(p_st_private->p_cmd,"UID ", 4) == 0)
            {
                snprintf(arr_tmp1, sizeof(arr_tmp1), "%s %s", p_st_private->p_cmd + 4, "complete\r\n");
                snprintf(arr_tmp2, sizeof(arr_tmp2), "%s %s", p_st_private->p_cmd + 4, "completed\r\n");
            }
            else
            {
                snprintf(arr_tmp1, sizeof(arr_tmp1), "%s %s", p_st_private->p_cmd, "complete\r\n");
                snprintf(arr_tmp2, sizeof(arr_tmp2), "%s %s", p_st_private->p_cmd, "completed\r\n");
            }
            frfree(p_st_private->p_cmd);
            p_st_private->p_cmd=NULL;
            //查找最后一个\r\n（在末尾不计）。
            p_pos = nefrmemstr(p_st_packet->p_payload, p_st_packet->ui_payload_len, (char *)"\r\n", 2);
            //多行响应情况
            if (p_pos != NULL)
            {
                if (*(p_st_packet->p_payload+p_st_packet->ui_payload_len-2) == '\r'
                    && *(p_st_packet->p_payload+p_st_packet->ui_payload_len-1) == '\n')
                {
                    if (strcasecmp(p_st_packet->p_payload+p_st_packet->ui_payload_len-strlen(arr_tmp1), arr_tmp1)==0
                        || strcasecmp(p_st_packet->p_payload+p_st_packet->ui_payload_len-strlen(arr_tmp2), arr_tmp2)==0
                        || strcasecmp(arr_tmp1, "login complete\r\n")==0
                        || strcasecmp(arr_tmp1, "create complete\r\n")==0
                        || strcasecmp(arr_tmp1, "delete complete\r\n")==0
                        || strcasecmp(arr_tmp1, "rename complete\r\n")==0)
                    {
                        if (p_st_private->p_stay != NULL)
                            frfree(p_st_private->p_stay);
                        //resp解析
                        i_ret = __resp_parse(p_pos+2, p_st_packet->ui_payload_len-(p_pos-p_st_packet->p_payload)-2, p_st_private, p_st_private->p_st_body_data_resp, p_st_conn);
                        if (i_ret != APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC))
                            return i_ret;
                        i_flag_todo = 0;
                    }
                    if (i_flag_todo)
                        return APM_L7_ANALYZE_TODO;
                }

                if (i_flag_todo)
                {
                    p_st_private->i_response_sign = 1;
                    if (p_st_private->p_stay != NULL)
                        frfree(p_st_private->p_stay);
                    p_st_private->p_stay = (char *)frmalloc(p_st_packet->ui_payload_len-(p_pos-p_st_packet->p_payload)-1);
                    if (p_st_private->p_stay == NULL)
                        goto ERROR;
                    snprintf(p_st_private->p_stay,p_st_packet->ui_payload_len-(p_pos-p_st_packet->p_payload)-1, "%s", p_pos+2);
                    return APM_L7_ANALYZE_TODO;
                }
            }
            //单行响应情况
            else if (p_st_private->i_response_sign == 1)
            {
                p_tmp = (char *)frmalloc(strlen(p_st_private->p_stay)+strlen(p_st_packet->p_payload)+1);
                if (p_tmp == NULL)
                    goto ERROR;
                memset(p_tmp, 0x00, strlen(p_st_private->p_stay)+strlen(p_st_packet->p_payload)+1);
                snprintf(p_tmp, strlen(p_st_private->p_stay)+strlen(p_st_packet->p_payload)+1, "%s%s", p_st_private->p_stay, p_st_packet->p_payload);
                //resp解析
                i_ret = __resp_parse(p_tmp, strlen(p_st_private->p_stay)+strlen(p_st_packet->p_payload)+1, p_st_private, p_st_private->p_st_body_data_resp, p_st_conn);
                frfree(p_st_private->p_stay);
                if (i_ret != APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC))
                    return i_ret;
            }
            else if (strcasecmp(p_st_packet->p_payload+p_st_packet->ui_payload_len-strlen(arr_tmp1), arr_tmp1)==0
                    || strcasecmp(p_st_packet->p_payload+p_st_packet->ui_payload_len-strlen(arr_tmp2), arr_tmp2)==0
                    || strcasecmp(arr_tmp1, "login complete\r\n")==0
                    || strcasecmp(arr_tmp1, "create complete\r\n")==0
                    || strcasecmp(arr_tmp1, "delete complete\r\n")==0
                    || strcasecmp(arr_tmp1, "rename complete\r\n")==0)
            {
                if (p_st_private->p_stay != NULL)
                    frfree(p_st_private->p_stay);
                //resp解析
                i_ret = __resp_parse(p_st_packet->p_payload, p_st_packet->ui_payload_len, p_st_private, p_st_private->p_st_body_data_resp, p_st_conn);
                if (i_ret != APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC))
                    return i_ret;
            }
            else
                return APM_L7_ANALYZE_TODO;
        }
        else
        {
            if (frmemstr(p_st_packet->p_payload, p_st_packet->ui_payload_len, (char *)"Server ready", 12) != NULL)
            {
                //resp解析
                i_ret = __resp_parse(p_st_packet->p_payload, p_st_packet->ui_payload_len, p_st_private, p_st_private->p_st_body_data_resp, p_st_conn);
                if (i_ret != APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC))
                    return i_ret;
            }

        }
    }

    switch(p_st_private->i_flag_data_type)
    {
        case 2:
		        p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGON, p_st_private->p_user_name, &p_st_packet->st_timestamp);
		        if (p_st_report_data)
		        {
		            if (frreport_send(g_p_apm_context, &p_st_report_data) == FR_FAIL)
		                goto ERROR;
		        }
		        break;
        case 3:
		        p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGON_REJECT, p_st_private->p_user_name, &p_st_packet->st_timestamp);
		        if (p_st_report_data)
		        {
		            if (frreport_send(g_p_apm_context, &p_st_report_data) == FR_FAIL)
		                goto ERROR;
		        }
		        break;
        case 5:
		        p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGOUT, p_st_private->p_user_name, &p_st_packet->st_timestamp);
		        if (p_st_report_data)
		        {
		            if (frreport_send(g_p_apm_context, &p_st_report_data) == FR_FAIL)
		                goto ERROR;
		        }
		        break;
        default:
            break;
    }

    //数据上报
    //st_response_time
    p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    //请求的字节数
    p_st_l4_trans->l_response_bytes += p_st_packet->ui_payload_len;
    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_l4_trans->l_response_bytes) == FR_FAIL)
        goto ERROR;

    //down load time
    ul_tmp = frtime_diff(&(p_st_l4_trans->st_response_time_first_byte), &(p_st_l4_trans->st_response_time));
    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    //end time
    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_l4_trans->st_response_time) == FR_FAIL)
        goto ERROR;

    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
    if (p_st_report_data == NULL)
        goto ERROR;

    if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_resp) == FR_FAIL)
        goto ERROR;
    p_st_private->p_st_body_data_resp = NULL;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
        goto ERROR;
    p_st_report_data = NULL;

    //返回值设置
    i_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
    switch(p_st_private->i_flag_data_type)
    {
        case ( 2 ):
        case ( 3 ):
            i_ret = APM_L7_ANALYZE_SET_LOGIN(i_ret);
            break;
        case ( 5 ):
            i_ret = APM_L7_ANALYZE_SET_LOGOUT(i_ret);
            break;
        default:
            break;
    }
    __imap_session_reset((void *)(p_st_private));

    return i_ret;

ERROR:
    if (p_tmp)
        frfree(p_tmp);
    if (p_st_report_data)
        frreport_data_free(&p_st_report_data);
    __imap_session_reset((void *)(p_st_private));

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * imap的packet解析
 *
 * \param p_st_conn          (入力链接信息)
 * \param p_st_packet        (入力packet信息)
 * \param p_st_hash_report   (保存Frreport_data)
 *
 * \return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC)    成功\n
 *         APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC)   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *
 * \note
 *
 */
int imap_analysis(Conntrack *p_st_conn
                  , Apm_packet *p_st_packet
                  , Frhash_header *p_st_hash_report)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_session *p_st_session = NULL;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    //到Conntrack中取得session信息
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //fin、syn包销毁私有数据
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        imap_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    //p_session_private分配内存
    if (p_st_session->p_session_private == NULL)
    {
        p_st_session->p_session_private = __imap_private_create();
        //内存分配失败
        if (p_st_session->p_session_private == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    //request
    if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
    {
        i_ret = __req_data_analysis(p_st_conn,p_st_packet,p_st_hash_report,p_st_session);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        return i_ret;
    }
    //response
    else
    {
        i_ret = __resp_data_analysis(p_st_conn,p_st_packet,p_st_hash_report, p_st_session);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        return i_ret;
    }

ERROR:
    if (p_st_session->p_session_private)
        imap_session_destroy(p_st_session->p_session_private);
    p_st_session->p_session_private = NULL;
    return APM_L7_ANALYZE_FAIL;

}

/*!
 * 私有信息销毁
 *
 * \param p_private_session  (imap的私有session数据)
 *
 * \return FR_SUCC   成功\n
 *
 * \note
 *
 */
int imap_session_destroy(void *p_private_session)
{
    L7session_imap_private *p_st_private = (L7session_imap_private*)p_private_session;

    if (p_st_private)
    {
        if (p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        if (p_st_private->p_st_body_data_resp)
            frreport_body_free(&p_st_private->p_st_body_data_resp);

        if (p_st_private->p_lst_req)
            frreport_body_l7list_free(&p_st_private->p_lst_req);

        if (p_st_private->p_lst_comm)
            frreport_body_l7list_free(&p_st_private->p_lst_comm);

        if (p_st_private->p_header_name)
            frfree(p_st_private->p_header_name);

        if (p_st_private->p_user_name)
            frfree(p_st_private->p_user_name);

        if (p_st_private->p_stay)
            frfree(p_st_private->p_stay);

        if (p_st_private->p_cmd)
            frfree(p_st_private->p_cmd);

        frfree(p_st_private);
    }
    return FR_SUCC;
}
